﻿/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using CSharpKit.Threading.Tasks;

namespace CSharpKit.Numerics.LinearAlgebra
{
    /// <summary>
    /// 密集矢量存储器
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [Serializable]
    public class VectorStorageDense<T> : VectorStorage<T>
        where T : struct, IEquatable<T>, IFormattable
    {
        #region Constructors

        public VectorStorageDense(int length)
            : this(length, new T[length]) { }

        public VectorStorageDense(int length, T[] data)
            : base(length)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            if (data.Length != length)
            {
                throw new ArgumentOutOfRangeException(nameof(data),
                    string.Format(Resources.Numerics.ArgumentArrayWrongLength, length));
            }

            _Data = data;

            // _Data = new T[length];
            // Array.Copy(_Data, data, length); // syc

            _IsDense = true;
        }

        #endregion


        #region Data - 数据

        private readonly T[] _Data;

        [DataMember(Order = 1)]
        public T[] Data => _Data;

        #endregion


        internal override T At(int index)
        {
            return Data[index];
        }

        internal override void At(int index, T tvalue)
        {
            Data[index] = tvalue;
        }


        public static VectorStorageDense<T> OfValue(int length, T value)
        {
            if (length < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(length), string.Format(Resources.Numerics.ArgumentLessThanOne, length));
            }

            if (Zero.Equals(value))
            {
                return new VectorStorageDense<T>(length);
            }

            var data = new T[length];
            CommonParallel.For(0, data.Length, 4096, (a, b) =>
            {
                for (int i = a; i < b; i++)
                {
                    data[i] = value;
                }
            });
            return new VectorStorageDense<T>(length, data);
        }

        public static VectorStorageDense<T> OfInit(int length, Func<int, T> finit)
        {
            if (length < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(length), string.Format(Resources.Numerics.ArgumentLessThanOne, length));
            }

            var data = new T[length];
            CommonParallel.For(0, data.Length, 4096, (a, b) =>
            {
                for (int i = a; i < b; i++)
                {
                    data[i] = finit(i);
                }
            });
            return new VectorStorageDense<T>(length, data);
        }

        public static VectorStorageDense<T> OfEnumerable(IEnumerable<T> data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var arrayData = data as T[];
            if (arrayData != null)
            {
                var copy = new T[arrayData.Length];
                Array.Copy(arrayData, 0, copy, 0, arrayData.Length);
                return new VectorStorageDense<T>(copy.Length, copy);
            }

            var array = data.ToArray();
            return new VectorStorageDense<T>(array.Length, array);
        }






        //}}@@@
    }


}
